#include <QDir>
#include <QApplication>
#include <QDebug>
#include <QSettings>
#include <QTextCodec>
#include <QJsonObject>

#include "qlspluginsmanager.h"

/* -------------------- 插件信息类 -------------------- */
/* 构造函数 */
PluginInfo::PluginInfo() :
	m_loader(nullptr),
	m_interface(nullptr),
	m_interfaceInfo(nullptr),
	m_isLoaded(false)
{
}

/* 运算符重载 == */
bool PluginInfo::operator ==(const PluginInfo &other)
{
	return this->m_loader == other.m_loader;
}

/* 运算符重载 >> */
QList<PluginInfo> &PluginInfo::operator >>(QList<PluginInfo> &list)
{
	for(auto it = list.begin(); it != list.end(); it++)
	{
		/* 如果存在该插件，更新其他信息 */
		if(*it == *this)
		{
			if(it->m_interface != this->m_interface) it->m_interface = this->m_interface;
			if(it->m_interfaceInfo != this->m_interfaceInfo) it->m_interfaceInfo = this->m_interfaceInfo;
			if(it->m_absFilename != this->m_absFilename) it->m_absFilename = this->m_absFilename;
			if(it->m_filename != this->m_filename) it->m_filename = this->m_filename;
			if(it->m_isLoaded != this->m_isLoaded) it->m_isLoaded = this->m_isLoaded;
			return list;
		}
	}
	/* 不存在则直接插入列表 */
	list.push_back(*this);
	return list;
}

/* -------------------- 插件管理类 -------------------- */
QLsPluginsManager::QLsPluginsManager(QString pluginsDir/*  = "plugins/QCoreSystem" */) :
	m_themesManager(new QLsThemesManager(QString("themes/%1").arg(pluginsDir))),
	m_pluginsDir(pluginsDir),
	m_pluginsIniDir(QString("ini/%1.ini").arg(pluginsDir))
{
}

QLsPluginsManager::~QLsPluginsManager()
{
	UnloadAllPlugin();
}

/* 运算符重载 == */
bool QLsPluginsManager::operator ==(const QLsPluginsManager &other)
{
	return this->m_pluginsDir == other.pluginsDir();
}

/* 插件路径 */
QString QLsPluginsManager::pluginsDir() const
{
	return m_pluginsDir;
}

void QLsPluginsManager::setPluginsDir(const QString &pluginsDir)
{
	m_pluginsDir = pluginsDir;
	m_pluginsIniDir = QString("ini/%1.ini").arg(pluginsDir);
}

/* 插件信息配置文件路径 */
QString QLsPluginsManager::pluginsIniDir() const
{
	return m_pluginsIniDir;
}

/* 更新本地插件：只获取信息，不直接加载 */
void QLsPluginsManager::RefreshLocalPlugins()
{
	/* 遍历插件库 */
	QDir pluginsDir = QDir(qApp->applicationDirPath());
	if(!pluginsDir.cd(m_pluginsDir)) return;

	foreach (QString fileName, pluginsDir.entryList(QDir::Files))
	{
		/* 加载插件 */
		QPluginLoader *pluginLoader = new QPluginLoader(pluginsDir.absoluteFilePath(fileName));

		/* 通过元数据匹配校验插件 */
		if(pluginLoader->metaData()["IID"].toString() != "com.Interface.QLsInterface")
		{
			if(pluginLoader)
			{
				delete pluginLoader;
				pluginLoader = nullptr;
			}
			continue;
		}

		/* 插入列表 */
		PluginInfo info;
		info.m_loader = pluginLoader;
		info.m_interfaceInfo = new InterfaceInfo(
					pluginLoader->metaData()["MetaData"].toObject());
		info.m_absFilename = pluginsDir.absoluteFilePath(fileName);
		info.m_filename = fileName;

		/* 只获取信息，不加载 */
		info.m_interface = nullptr;
		info.m_isLoaded = false;
		info >> m_pluginsList;
	}
}

/* 加载插件 */
bool QLsPluginsManager::LoadPlugin(PluginInfo &info)
{
	if(info.m_loader->isLoaded()) return true;

	/* 加载插件 */
	if(!info.m_loader->load()) return false;

	/* 获取插件唯一实例 */
	QObject *plugin = info.m_loader->instance();
	if(plugin)
	{
		/* 获取插件接口 */
		QLsInterface *centerInterface = qobject_cast<QLsInterface*>(plugin);
		if(centerInterface)
		{
			/* 更新插件信息 */
			info.m_interface = centerInterface;
			info.m_isLoaded = info.m_loader->isLoaded();
			info >> m_pluginsList;
			return true;
		}
	}

	return false;
}
bool QLsPluginsManager::LoadPlugin(const QString &filename)
{
	/* 当前是否已存在该插件，如果已存在，不需读取，直接加载 */
	foreach (PluginInfo info, m_pluginsList)
		if(info.m_filename == filename)
			return LoadPlugin(info);

	/* 遍历插件库 */
	QDir pluginsDir = QDir(qApp->applicationDirPath());
	if(!pluginsDir.cd(m_pluginsDir)) return false;

	/* 加载插件 */
	QPluginLoader *pluginLoader = new QPluginLoader(pluginsDir.absoluteFilePath(filename));
	if(pluginLoader->metaData()["IID"].toString() != "com.Interface.QLsInterface" ||
			!pluginLoader->load())
	{
		if(pluginLoader)
		{
			delete pluginLoader;
			pluginLoader = nullptr;
		}
		return false;
	}

	/* 获取插件唯一实例 */
	QObject *plugin = pluginLoader->instance();
	if(plugin)
	{
		/* 获取插件接口 */
		QLsInterface *centerInterface = qobject_cast<QLsInterface*>(plugin);
		if(centerInterface)
		{
			/* 插入列表 */
			PluginInfo info;
			info.m_loader = pluginLoader;
			info.m_interface = centerInterface;
			info.m_interfaceInfo = new InterfaceInfo(
						pluginLoader->metaData()["MetaData"].toObject());
			info.m_absFilename = pluginsDir.absoluteFilePath(filename);
			info.m_filename = filename;
			info.m_isLoaded = pluginLoader->isLoaded();
			info >> m_pluginsList;
			return true;
		}
	}

	return false;
}

QList<PluginInfo> QLsPluginsManager::GetPluginsList() const
{
	return m_pluginsList;
}

/* 卸载全部插件 */
void QLsPluginsManager::UnloadAllPlugin()
{
	foreach (PluginInfo info, m_pluginsList)
	{
		/* 只卸载插件，释放接口，不清除插件信息 */
		if(info.m_isLoaded && info.m_loader->unload())
		{
			info.m_interface = nullptr;
			info.m_isLoaded = false;
			info >> m_pluginsList;
		}
	}
}

/* 卸载插件 */
bool QLsPluginsManager::UnloadPlugin(PluginInfo &info)
{
	/* 原来就是未加载状态，则直接返回卸载成功 */
	if(!info.m_isLoaded) return true;
	/* 卸载并成功 */
	if(info.m_isLoaded && info.m_loader->unload())
	{
		info.m_interface = nullptr;
		info.m_isLoaded = false;
		info >> m_pluginsList;
		return true;
	}
	/* 卸载失败 */
	return false;
}
bool QLsPluginsManager::UnloadPluginByFilename(const QString &filename)
{
	/* 找到并卸载：相对路径 */
	foreach (PluginInfo info, m_pluginsList)
		if(info.m_filename == filename)
			return UnloadPlugin(info);
	/* 没有该插件 */
	return false;
}
bool QLsPluginsManager::UnloadPluginByAbsFilename(const QString &absFilename)
{
	/* 找到并卸载：绝对路径 */
	foreach (PluginInfo info, m_pluginsList)
		if(info.m_absFilename == absFilename)
			return UnloadPlugin(info);
	/* 没有该插件 */
	return false;
}

/* 根据插件名获取插件信息 */
PluginInfo QLsPluginsManager::GetPluginInfoByInterfaceName(const QString &interfaceName)
{
	foreach (PluginInfo info, m_pluginsList)
	{
		if(info.m_interfaceInfo->m_name == interfaceName)
			return info;
	}
	return PluginInfo();
}

/* 检查必装插件是否加载 */
bool QLsPluginsManager::CheckMustLoadPlugins()
{
	/* 打开插件配置文件 */
	QSettings settings(m_pluginsIniDir, QSettings::IniFormat);
	settings.setIniCodec(QTextCodec::codecForName("UTF-8"));

	/* 遍历全部插件 */
	foreach (QString pluginName, settings.childGroups())
	{
		/* 找到必装插件 */
		settings.beginGroup(pluginName);
		if(settings.value("level", 0).toInt() != 1) continue;

		/* 判断是否存在 */
		bool flag = false;
		foreach (PluginInfo info, m_pluginsList)
		{
			if(info.m_filename == pluginName)
			{
				flag = true;
				break;
			}
		}

		/* 如果没有，则将插件文件名存入列表 */
		if(!flag)
			m_mustLoadButDisload << pluginName;
	}

	return m_mustLoadButDisload.count() == 0;
}

QStringList QLsPluginsManager::mustLoadButDisload() const
{
	return m_mustLoadButDisload;
}

QLsThemesManager *QLsPluginsManager::themesManager() const
{
	return m_themesManager;
}

